import pdb

import pygame
import sys
from pygame.locals import DOUBLEBUF, MOUSEBUTTONDOWN, QUIT, KEYDOWN,K_ESCAPE,K_RETURN
import Box2D as box2d
import ToolBox
import Box2D as box2d

class fwContactPoint:
    """
    Structure holding the necessary information for a contact point.
    All of the information is copied from the contact listener callbacks.
    """
    shape1 = None
    shape2 = None
    normal = None
    position = None
    velocity = None
    id  = box2d.b2ContactID()
    state = 0
    
class fwContactTypes:
    """
    Acts as an enum, holding the types necessary for contacts:
    Added, persisted, and removed
    """
    contactUnknown = 0
    contactAdded = 1
    contactPersisted = 2
    contactRemoved = 3
    
class fwContactListener(box2d.b2ContactListener):
    """
    Handles all of the contact states passed in from Box2D.

    """
    test = None
    def __init__(self):
        super(fwContactListener, self).__init__()

    def handleCall(self, state, point):
        if not self.test: return

        cp          = fwContactPoint()
        cp.shape1   = point.shape1
        cp.shape2   = point.shape2
        cp.position = point.position.copy()
        cp.normal   = point.normal.copy()
        cp.id       = point.id
        cp.state    = state
        self.test.points.append(cp)

    def Add(self, point):
        self.handleCall(fwContactTypes.contactAdded, point)

    def Persist(self, point):
        self.handleCall(fwContactTypes.contactPersisted, point)

    def Remove(self, point):
        self.handleCall(fwContactTypes.contactRemoved, point)

class GameModes:
	ADVANCING_TO_NEXT_LEVEL=1
	PAUSE=2
	IN_LEVEL=3
	MAIN_MENU=4
	
class Game(object):

    def __init__(self):

        self.screen_size = (800,600)
        self.max_fps = 60        
        self.box2d_init()
        self.mode=GameModes.MAIN_MENU
        
    def pygame_init(self):
        """starts pygame"""

        pygame.init()
        self.screen = pygame.display.set_mode(self.screen_size ,DOUBLEBUF, 32)
        self.clock = pygame.time.Clock()

    def box2d_init(self):
        """ starts box2d and adds initial objects """

        self.world = self.make_world()
        self.contactListener = fwContactListener()
        #add to the contact listener a reference to self so it can set self.points
        self.contactListener.test = self
        self.world.SetContactListener(self.contactListener)
        self.make_start_shapes()

    def make_start_shapes(self):
        """ add all initial shapes in here
        subclass this and overwrite"""

        ballbodydef = box2d.b2BodyDef()
        ballbodydef.position = (0,-0)
        ballbodydef.isBullet = True
        ballbodydef.angularDamping = 1000000
        ballbodydef.userData = dict(name ="poo")
        ballshapedef = box2d.b2CircleDef()
        ballshapedef.density = 0.1 
        ballshapedef.friction = 0
        ballshapedef.restitution = 0.8 
        ballshapedef.radius = 2
        ballshapedef.userData = dict(name ="poo")
        ball = self.world.CreateBody(ballbodydef)
        ball.CreateShape(ballshapedef)
        ball.SetMassFromShapes()
        self.add_body(ball)

        bodyDef = box2d.b2BodyDef()
        bodyDef.position = (0, -5)
        bodyDef.angularDamping = 1000000
        bodyDef.fixedRotation = True
        bodyDef.userData = dict(name ="poo")
        body = self.world.CreateBody(bodyDef)
        shapeDef = box2d.b2PolygonDef()
        shapeDef.SetAsBox(6, 0.8)
        shapeDef.density = 0.1
        shapeDef.friction = 0
        shapeDef.restitution = 1 
        shapeDef.userData = dict(name ='bat')
        body.CreateShape(shapeDef)
        body.SetMassFromShapes()
        self.add_body(body)

    def make_world(self):
        """makes box2d world"""

        worldAABB=box2d.b2AABB()
        worldAABB.lowerBound = (-40.0, -30.0)
        worldAABB.upperBound = ( 40.0, 30.0)
        gravity = (0.0, 0.0)
        world = box2d.b2World(worldAABB, gravity, True)
        return world

    def run(self):
        """ main run loop """

        self.pygame_init()

        self.running =True
        while self.running:
            for event in pygame.event.get():
                if event.type == QUIT or (event.type == KEYDOWN and event.key == K_ESCAPE):
                    self.running = False            
            if self.mode == GameModes.IN_LEVEL:
                # Reset the collision points
                self.points = []
                self.physics_step()
                self.screen.fill( (0,0,0) )
                self.handle_collisions()
                self.draw()
                pygame.display.flip()
                self.clock.tick(self.max_fps)
                self.check_game_conditions()
            if self.mode == GameModes.ADVANCING_TO_NEXT_LEVEL:
                self.screen.fill( (0,0,0) )
                self.drawBetweenLevels()
                pygame.display.flip()
                self.clock.tick(self.max_fps)
                self.check_game_conditions()
            if self.mode == GameModes.MAIN_MENU:
                self.screen.fill( (0,0,0) )
                self.draw_main_menu()
                pygame.display.flip()
                self.clock.tick(self.max_fps)
                self.check_game_conditions()

	def check_game_conditions(self):
		"""In here we check the rules of the game and set appropriate variables example:
		Something is in a particular area of the screen that causes a life to be lost
		The condition is met to advance to the next level
		"""
		
		pass
		
    def handle_collisions(self):
        """Code to iterate through collision points from the last step and do stuff with them Assumes self.points is set by the contact listener added to the world"""    
        k_axisScale = 0.3
        for point in self.points:
            if point.state == fwContactTypes.contactAdded:
                print "collision point added %s"%point.position
                #self.debugDraw.DrawPoint(point.position, settings.pointSize, box2d.b2Color(0.3, 0.95, 0.3))
            elif point.state == fwContactTypes.contactPersisted:
                print "collision point persisted %s"%point.position
                #self.debugDraw.DrawPoint(point.position, settings.pointSize, box2d.b2Color(0.3, 0.3, 0.95))
            else: #elif point.state == fwContactTypes.contactRemoved:
                print "collision point removed %s"%point.position
                #self.debugDraw.DrawPoint(point.position, settings.pointSize, box2d.b2Color(0.95, 0.3, 0.3))

            p1 = point.position
            p2 = p1 + k_axisScale * point.normal
            #self.debugDraw.DrawSegment(p1, p2, box2d.b2Color(0.4, 0.9, 0.4))
					
    def physics_step(self, vel_iter = 8, pos_iter = 8):
        """the box2d pysics step"""
        self.physics()
        self.world.Step( 1.0/self.max_fps , vel_iter, pos_iter)

    def physics(self):
        """ pyhsics during loop goes here"""
        pass

    def draw(self):
        """draw all shapes"""
        for body in self.world:
            if body.userData!= None and body.userData.has_key("invisible") and body.userData["invisible"]:
                continue
            for shape in body:
                if shape.__class__.__name__ == 'b2CircleShape':
                    pygame.draw.circle(self.screen, (100,10,60), 
                           ToolBox.shape_to_screen(shape), 
                           20, 2)
                if shape.__class__.__name__ == 'b2PolygonShape':
                    pygame.draw.polygon(self.screen, (100,10,60), 
                           ToolBox.shapevert_to_screen(shape), 
                            2)
                              
    def drawBetweenLevels(self):
        """What to draw in the transition between levels."""
        font = pygame.font.Font(None, 36)
        text = font.render("Well Done to have advanced to the next level!", 1, (255, 255, 255))
        textpos = text.get_rect(centerx=self.screen.get_width()/2)
        self.screen.blit(text, textpos)    
    
    def draw_main_menu(self):
        """Draw the menu."""
        font = pygame.font.Font(None, 36)
        text = font.render("Please press enter to start playing", 1, (255, 255, 255))
        textpos = text.get_rect(centerx=self.screen.get_width()/2)
        self.screen.blit(text, textpos)
        
if __name__ == "__main__":

   game4327 = Game()
   game4327.run()
   sys.exit(0)
